#pragma once
extern "C"
{
#include "avcodec.h"
#include "avformat.h"
#include "swscale.h"
}

#ifndef LINUX_NAS
///////////////////////////////////////////////////

typedef __declspec(dllexport) struct AVFrame* g_avcodec_alloc_frame();
typedef __declspec(dllexport) int g_avcodec_encode_video(AVCodecContext *avctx, uint8_t *buf, int buf_size, const AVFrame *pict);
typedef __declspec(dllexport) int g_avcodec_decode_video(AVCodecContext *avctx, AVFrame *picture, int *got_picture_ptr, const uint8_t *buf, int buf_size);
typedef __declspec(dllexport) int g_avcodec_encode_audio(AVCodecContext *avctx, uint8_t *buf, int buf_size, const short *samples);
typedef __declspec(dllexport) int g_av_find_stream_info(AVFormatContext *ic);
typedef __declspec(dllexport) AVCodec *g_avcodec_find_decoder(enum CodecID id);
typedef __declspec(dllexport) int g_avcodec_open(AVCodecContext *avctx, AVCodec *codec);
typedef __declspec(dllexport) int g_avpicture_get_size(int pix_fmt, int width, int height);
typedef __declspec(dllexport) int g_avpicture_fill(AVPicture *picture, uint8_t *ptr,
												   int pix_fmt, int width, int height);
typedef __declspec(dllexport) int g_avcodec_decode_audio2(AVCodecContext *avctx, int16_t *samples,
														  int *frame_size_ptr,
														  const uint8_t *buf, int buf_size);
typedef __declspec(dllexport) int g_avcodec_close(AVCodecContext *avctx);

typedef __declspec(dllexport) void g_avcodec_init(void);
typedef __declspec(dllexport) void g_avcodec_register_all(void);
typedef __declspec(dllexport) AVCodec *g_avcodec_find_encoder(enum CodecID id);
typedef __declspec(dllexport) void g_avcodec_get_context_defaults(AVCodecContext *s);
typedef __declspec(dllexport) void g_avcodec_get_context_defaults2(AVCodecContext *s, enum CodecType);
typedef __declspec(dllexport) AVCodecContext * g_avcodec_alloc_context(void);

typedef __declspec(dllexport) int g_av_read_packet(AVFormatContext *s, AVPacket *pkt);
typedef __declspec(dllexport) int g_av_open_input_file(AVFormatContext **ic_ptr, const char *filename,
													   AVInputFormat *fmt,
													   int buf_size,
													   AVFormatParameters *ap);
typedef __declspec(dllexport) void g_av_close_input_file(AVFormatContext *s);
typedef __declspec(dllexport) AVOutputFormat * g_guess_format(const char *short_name,
															  const char *filename,
															  const char *mime_type);
typedef __declspec(dllexport) AVFormatContext * g_av_alloc_format_context(void);
typedef __declspec(dllexport) int g_av_write_header(AVFormatContext *s);
typedef __declspec(dllexport) int g_av_metadata_set(AVMetadata **pm, const char *key, const char *value, int flags);
typedef __declspec(dllexport) int g_av_write_frame(AVFormatContext *s, AVPacket *pkt);
typedef __declspec(dllexport) int g_av_set_parameters(AVFormatContext *s, AVFormatParameters *ap);
typedef __declspec(dllexport) void g_dump_format(AVFormatContext *ic,
												 int index,
												 const char *url,
												 int is_output);
typedef __declspec(dllexport) void g_av_register_all(void);
typedef __declspec(dllexport) AVStream * g_av_new_stream(AVFormatContext *s, int id);
typedef __declspec(dllexport) int g_url_fopen(ByteIOContext **s, const char *filename, int flags);
typedef __declspec(dllexport) int g_url_fclose(ByteIOContext *s);
typedef __declspec(dllexport) void g_av_init_packet(AVPacket *pkt);
typedef __declspec(dllexport) int g_av_write_trailer(AVFormatContext *s);

typedef __declspec(dllexport) void g_av_free(void *ptr);
typedef __declspec(dllexport) int64_t g_av_rescale_q(int64_t a, AVRational bq, AVRational cq) av_const;

typedef __declspec(dllexport) struct SwsContext *g_sws_getContext(int srcW, int srcH, int srcFormat, int dstW, int dstH, int dstFormat, int flags,
																  SwsFilter *srcFilter, SwsFilter *dstFilter, double *param);
typedef __declspec(dllexport) int g_sws_scale(struct SwsContext *context, uint8_t* src[], int srcStride[], int srcSliceY,
											  int srcSliceH, uint8_t* dst[], int dstStride[]);
typedef __declspec(dllexport) void g_sws_freeContext(struct SwsContext *swsContext);;
typedef __declspec(dllexport) AVOutputFormat *g_av_oformat_next(AVOutputFormat *f);
typedef __declspec(dllexport) void g_av_log_set_callback(void (*)(void*, int, const char*, va_list));

typedef __declspec(dllexport) int g_av_interleaved_write_frame(AVFormatContext *s, AVPacket *pkt);
//typedef __declspec(dllexport) AVFormatContext * g_avformat_alloc_context(void);
typedef __declspec(dllexport) void *g_av_malloc(unsigned int size);
typedef __declspec(dllexport) int g_av_read_frame(AVFormatContext *s, AVPacket *pkt);
typedef __declspec(dllexport) int g_av_seek_frame(AVFormatContext *s, int stream_index, int64_t timestamp, int flags);
typedef __declspec(dllexport) void g_av_free_parcket(AVPacket *pkt);

#endif

static void* g_ptr_ffmpeg_instance_singleton = NULL;
///////////////////////////////////////////////////////////////////////////////////////////

class CFFMpegInstance
{
private:
	CFFMpegInstance(void);

public:
	~CFFMpegInstance(void);

public:
	static CFFMpegInstance* GetInstance()
	{
		if(g_ptr_ffmpeg_instance_singleton == NULL)
			g_ptr_ffmpeg_instance_singleton = new CFFMpegInstance();

		return (CFFMpegInstance*)g_ptr_ffmpeg_instance_singleton;
	}
#ifndef LINUX_NAS
public:
	CRITICAL_SECTION g_lock;
	g_avcodec_alloc_frame* f_avcodec_alloc_frame;
	g_av_read_packet* f_av_read_packet;
	g_avcodec_encode_video* f_avcodec_encode_video;
	g_avcodec_decode_video* f_avcodec_decode_video;
	g_avcodec_encode_audio* f_avcodec_encode_audio;
	g_avcodec_find_decoder* f_avcodec_find_decoder;
	g_avcodec_open* f_avcodec_open;
	g_avpicture_get_size* f_avpicture_get_size;
	g_avpicture_fill* f_avpicture_fill;
	g_av_close_input_file* f_av_close_input_file;
	g_avcodec_close* f_avcodec_close;
	g_avcodec_init* f_avcodec_init;
	g_avcodec_register_all* f_avcodec_register_all;
	g_avcodec_find_encoder* f_avcodec_find_encoder;
	g_avcodec_get_context_defaults* f_avcodec_get_context_defaults;
	g_avcodec_get_context_defaults2* f_avcodec_get_context_defaults2;
	g_avcodec_alloc_context* f_avcodec_alloc_context;
	g_avcodec_decode_audio2* f_avcodec_decode_audio2;


	g_dump_format* f_dump_format;
	g_av_register_all* f_av_register_all;
	g_av_find_stream_info* f_av_find_stream_info;
	g_av_open_input_file* f_av_open_input_file;
	g_guess_format* f_guess_format;
	g_av_alloc_format_context* f_av_alloc_format_context;
	g_av_write_header* f_av_write_header;
	g_av_metadata_set* f_av_metadata_set;
	g_av_write_frame* f_av_write_frame;
	g_av_set_parameters* f_av_set_parameters;
	g_av_new_stream* f_av_new_stream;
	g_url_fopen* f_url_fopen;
	g_url_fclose* f_url_fclose;
	g_av_init_packet* f_av_init_packet;
	g_av_write_trailer* f_av_write_trailer;


	g_av_free* f_av_free;
	g_av_rescale_q* f_av_rescale_q;

	g_sws_getContext* f_sws_getContext;
	g_sws_scale* f_sws_scale;
	g_sws_freeContext* f_sws_freeContext;

	g_av_oformat_next* f_av_oformat_next;
	g_av_log_set_callback* f_av_log_set_callback;

	g_av_interleaved_write_frame* f_av_interleaved_write_frame;
	//g_avformat_alloc_context* f_avformat_alloc_context;
	g_av_malloc* f_av_malloc;
	g_av_read_frame* f_av_read_frame;
	g_av_seek_frame* f_av_seek_frame;
	//g_av_free_parcket * f_av_free_packet;

#else
	pthread_mutex_t g_lock;
	struct AVFrame* f_avcodec_alloc_frame()
	{
		return avcodec_alloc_frame();
	}
	int f_av_read_packet(AVFormatContext *s, AVPacket *pkt)
	{
		return av_read_packet(s, pkt);
	}
	int f_avcodec_encode_video(AVCodecContext *avctx, uint8_t *buf, int buf_size, const AVFrame *pict)
	{
		return avcodec_encode_video(avctx, buf, buf_size, pict);
	}
	int f_avcodec_decode_video(AVCodecContext *avctx, AVFrame *picture, int *got_picture_ptr, const uint8_t *buf, int buf_size)
	{
		return avcodec_decode_video(avctx, picture, got_picture_ptr, buf, buf_size);
	}
	int f_avcodec_encode_audio(AVCodecContext *avctx, uint8_t *buf, int buf_size, const short *samples)
	{
		return avcodec_encode_audio(avctx, buf, buf_size, samples);
	}
	AVCodec* f_avcodec_find_decoder(enum CodecID id)
	{
		return avcodec_find_decoder(id);
	}
	int f_avcodec_open(AVCodecContext *avctx, AVCodec *codec)
	{
		return avcodec_open(avctx, codec);
	}
	int f_avpicture_get_size(int pix_fmt, int width, int height)
	{
		return avpicture_get_size(pix_fmt, width, height);
	}
	int f_avpicture_fill(AVPicture *picture, uint8_t *ptr, int pix_fmt, int width, int height)
	{
		return avpicture_fill(picture, ptr, pix_fmt, width, height);
	}
	void f_av_close_input_file(AVFormatContext *s)
	{
		av_close_input_file(s);
	}
	int f_avcodec_close(AVCodecContext *avctx)
	{
		return avcodec_close(avctx);
	}
	void f_avcodec_init()
	{
		avcodec_init();
	}
	void f_avcodec_register_all()
	{
		avcodec_register_all();
	}
	AVCodec* f_avcodec_find_encoder(enum CodecID id)
	{
		return avcodec_find_encoder(id);
	}
	void f_avcodec_get_context_defaults(AVCodecContext *s)
	{
		avcodec_get_context_defaults(s);
	}
	void f_avcodec_get_context_defaults2(AVCodecContext *s, enum CodecType id)
	{
		avcodec_get_context_defaults2(s, id);
	}
	AVCodecContext* f_avcodec_alloc_context()
	{
		return avcodec_alloc_context();
	}


	void f_dump_format(AVFormatContext *ic, int index, const char *url, int is_output)
	{
		dump_format(ic, index, url, is_output);
	}
	void f_av_register_all()
	{
		av_register_all();
	}
	int f_av_find_stream_info(AVFormatContext *ic)
	{
		return av_find_stream_info(ic);
	}
	int f_av_open_input_file(AVFormatContext **ic_ptr, const char *filename, AVInputFormat *fmt, int buf_size,
		AVFormatParameters *ap)
	{
		return av_open_input_file(ic_ptr, filename, fmt, buf_size, ap);
	}
	AVOutputFormat* f_guess_format(const char *short_name,
		const char *filename,
		const char *mime_type)
	{
		return guess_format(short_name, filename, mime_type);
	}
	AVFormatContext* f_av_alloc_format_context()
	{
		return av_alloc_format_context();
	}
	int f_av_write_header(AVFormatContext *s)
	{
		return av_write_header(s);
	}
	int f_av_write_frame(AVFormatContext *s, AVPacket *pkt)
	{
		return av_write_frame(s, pkt);
	}
	int f_av_set_parameters(AVFormatContext *s, AVFormatParameters *ap)
	{
		return av_set_parameters(s, ap);
	}
	AVStream* f_av_new_stream(AVFormatContext *s, int id)
	{
		return av_new_stream(s, id);
	}
	int f_url_fopen(ByteIOContext **s, const char *filename, int flags)
	{
		return url_fopen(s, filename, flags);
	}
	int f_url_fclose(ByteIOContext *s)
	{
		return url_fclose(s);
	}
	void f_av_init_packet(AVPacket *pkt)
	{
		av_init_packet(pkt);
	}
	int f_av_write_trailer(AVFormatContext *s)
	{
		return av_write_trailer(s);
	}

	void f_av_free(void *ptr)
	{
		av_free(ptr);
	}
	int64_t  f_av_rescale_q(int64_t a, AVRational bq, AVRational cq)
	{
		return av_rescale_q(a, bq, cq);
	}

	struct SwsContext* f_sws_getContext(int srcW, int srcH, int srcFormat, int dstW, int dstH, int dstFormat, int flags,
		SwsFilter *srcFilter, SwsFilter *dstFilter, double *param)
	{
		return sws_getContext(srcW, srcH, srcFormat, dstW, dstH, dstFormat, flags, srcFilter, dstFilter, param);
	}
	int f_sws_scale(struct SwsContext *context, uint8_t* src[], int srcStride[], int srcSliceY,
		int srcSliceH, uint8_t* dst[], int dstStride[])
	{
		return sws_scale(context, src, srcStride, srcSliceY, srcSliceH, dst, dstStride);
	}
	void f_sws_freeContext(struct SwsContext *swsContext)
	{
		sws_freeContext(swsContext);
	}

	AVOutputFormat *f_av_oformat_next(AVOutputFormat *f)
	{
		return av_oformat_next(f);
	}
	
	//typedef __declspec(dllexport) void g_av_log_set_callback(void (*)(void*, int, const char*, va_list));

	int f_av_interleaved_write_frame(AVFormatContext *s, AVPacket *pkt)
	{
		return av_interleaved_write_frame(s, pkt);
	}

	void f_av_malloc(unsigned int size)
	{
		return av_malloc(unsigned int size);
	}

	int f_av_read_frame(AVFormatContext *s, AVPacket *pkt)
	{
		return av_read_frame(s, pkt);
	}

	int f_av_seek_frame(AVFormatContext *s, int stream_index, int64_t timestamp, int flags)
	{
		return av_seek_frame(s, stream_index, timestamp, flags);
	}

	void f_av_free_parcket(AVPacket *pkt)
	{
		g_av_free_parcket(pkt);
	}	
#endif

	void f_av_free_packet(AVPacket *pkt);

	void f_lock();
	void f_unlock();
};
